package com.dark.sys.service.impl;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.dark.common.Constants;
import com.dark.common.repository.hibernate.HibernateDao;
import com.dark.common.utils.BeanUtils;
import com.dark.common.utils.security.Md5Utils;
import com.dark.common.web.model.DataGrid;
import com.dark.common.web.model.Page;
import com.dark.common.web.validate.AjaxResponse;
import com.dark.sys.entity.User;
import com.dark.sys.service.UserService;
import com.dark.sys.web.dto.UserDto;

@Service
public class UserServiceImpl extends HibernateDao<User, Integer> implements UserService {
	
	@Override
	public void add(UserDto dto) {
		String password = Constants.DEFAULT_PASSWORD ;
		User entity = new User() ;
		BeanUtils.copyNotNullProperties(dto, entity);
		
		entity.setDeleted(Boolean.FALSE);
		entity.setPassword((null != dto && !dto.getPassword().equals("")?dto.getPassword():password));
		entity.randomSalt();
		entity.setPassword(encryptPassword(entity.getUsername(), entity.getPassword(), entity.getSalt()));
		
		super.save(entity); 
		
		if(dto.isNotification()){
			System.out.println("邮件通知新增用户[用户名："+entity.getUsername()+", 密码："+password+"]");
			
		}
		
	}

	@CacheEvict(value="SystemUserCache", allEntries=true)
	@Override
	public void delete(boolean type, String ids) {
		if(null != ids && ids.length() > 0) {
			String[] split = ids.split(",") ;
			Map<String, Object> alias = new HashMap<String, Object>() ;
			alias.put("ids", split) ;
			if(type) {
				super.executeSQL("update sys_user t set t.deleted=1 where id in(:ids)", alias) ;
			} else {
				//恢复已删除的用户
				super.executeSQL("update sys_user t set t.deleted=0 where id in(:ids)", alias) ;
			}
		}
	}

	@Override
	public void deleteForPhysical(String ids) {
		if(null != ids && ids.length() > 0) {
			String[] split = ids.split(",") ;
			for (String id : split) {
				super.deleteById(Integer.parseInt(id));
			}
		}
	}

	@CacheEvict(value="SystemUserCache", key="#root.targetClass + (\"[#username=\"+#dto.username+\"]\")")
	@Override
	public void update(UserDto dto) {
		User entity = this.getEntity(dto.getId());
		BeanUtils.copyNotNullProperties(dto, entity, new String[]{"password", "salt", "createTime"});
		super.update(entity);
	}

	@Override
	public UserDto get(Integer id) {
		User entity = super.getEntity(id);
		UserDto dto = new UserDto() ;
		BeanUtils.copyNotNullProperties(entity, dto);
		return dto;
	}
	
	@Cacheable(value="SystemUserCache", key="#root.targetClass + (\"[#username=\"+#username+\"]\")")
	@Override
	public UserDto getByUsername(String username) {
		String queryString = "select t.* from sys_user t where t.username=? and t.deleted=?" ;
		return (UserDto) super.findUniqueSQL(queryString, new Object[]{username, false}, UserDto.class, false);
	}
	
	public DataGrid datagrid(UserDto dto) {
		DataGrid dg = new DataGrid() ;
		
		Page<UserDto> findByPage = this.findByPage(dto) ;
		dg.setTotal(((Integer)findByPage.getTotalNumber()).longValue());
		dg.setRows(findByPage.getDataRows()) ;
		
		return dg;
	}
	

	public Page<UserDto> findByPage(UserDto dto) {
		StringBuffer queryString = new StringBuffer("SELECT t.* FROM sys_user t WHERE 1=1") ;
		
		Map<String, Object> alias = new HashMap<String, Object>() ;
		queryString = addWhere(queryString, alias, dto) ;
		
		return super.findPageSQL(queryString.toString(), alias, User.class, false) ;
	}
	
	private StringBuffer addWhere(StringBuffer queryString, Map<String, Object> alias, UserDto dto) {
		if(null != dto) {
			if(null != dto.getId()) {
				queryString.append(" AND t.id=:id") ;
				alias.put("id", dto.getId()) ;
			}
			
			if(null != dto.getDeleted()) {
				if(null != dto.getDeleted() && !dto.getDeleted()) {
					queryString.append(" AND t.deleted=0") ;
				} else if(null != dto.getDeleted() && dto.getDeleted()) {
					queryString.append(" AND t.deleted=1") ;
				}
			}
			if(null != dto.getUsername() && !"".equals(dto.getUsername())) {
				queryString.append(" AND t.username = :username") ;
				alias.put("username", dto.getUsername()) ;
			}
			if(null != dto.getTruename() && !"".equals(dto.getTruename())) {
				queryString.append(" AND t.truename = :truename") ;
				alias.put("truename", dto.getTruename()) ;
			}
			if(null != dto.getEmail() && !"".equals(dto.getEmail())) {
				queryString.append(" AND t.email = :email") ;
				alias.put("email", dto.getEmail()) ;
			}
			if(null != dto.getSex() && !"".equals(dto.getSex())) {
				queryString.append(" AND t.sex = :sex") ;
				alias.put("sex", dto.getSex()) ;
			}
			if(null != dto.getMobile_phone_number() && !"".equals(dto.getMobile_phone_number())) {
				queryString.append(" AND t.mobile_phone_number = :mobile_phone_number") ;
				alias.put("mobile_phone_number", dto.getMobile_phone_number()) ;
			}
			if(null != dto.getStatus() && !"".equals(dto.getStatus())) {
				queryString.append(" AND t.status=:status") ;
				alias.put("status", dto.getStatus()) ;
			}
			if (dto.getStartTime() != null && !"".equals(dto.getStartTime())) {
				queryString.append(" AND date_format(t.createTime,'%Y-%m-%d')>= date_format(:startTime,'%Y-%m-%d')") ;
				alias.put("startTime", dto.getStartTime()) ;
			}
			if (dto.getEndTime() != null && !"".equals(dto.getEndTime())) {
				queryString.append(" AND date_format(t.createTime,'%Y-%m-%d')<= date_format(:endTime,'%Y-%m-%d')") ;
				alias.put("endTime", dto.getEndTime()) ;
			}
			if(dto.getQuickSearch() != null && !"".equals(dto.getQuickSearch())){
				queryString.append(" and ")
				.append("(")
				.append("t.username like '%%" + dto.getQuickSearch() + "%%'")
				.append(" or t.email like '%%" + dto.getQuickSearch() + "%%'")
				.append(" or t.mobile_phone_number like '%%" + dto.getQuickSearch() + "%%'")
				.append(" or t.truename like '%%" + dto.getQuickSearch() + "%%'")
				.append(")");
			}
		}
		return queryString;
	}
	
	@Override
	public AjaxResponse validateLogin(String username, String password) {
		
		UserDto user = getByUsername(username) ; ;
		if(null == user) {
			//未知账号
			throw new UnknownAccountException() ;
		} else {
			//账号锁定
			if(null != user.getStatus() && user.getStatus().equals("blocked")) {
				throw new LockedAccountException() ;
			}
			//验证密码
			if(matches(user, password)) {
				return new AjaxResponse(true, "验证成功，进入后台管理！", user) ; 
			} else {
				//密码不正确
				throw new IncorrectCredentialsException() ;
			}
		}
	}

	public boolean matches(UserDto user, String newPassword) {
        return user.getPassword().equals(encryptPassword(user.getUsername(), newPassword, user.getSalt()));
    }
	
	
	private String encryptPassword(String username, String password, String salt) {
		return Md5Utils.hash(username + password + salt);
	}

	@Override
	public boolean checkInfo(UserDto dto) {
		StringBuffer queryString = new StringBuffer("SELECT count(t.id) FROM sys_user t WHERE 1=1 ") ;
		
		Map<String, Object> alias = new HashMap<String, Object>() ;
		queryString = addWhere(queryString, alias, dto) ;
		
		BigInteger count = (BigInteger) super.findUniqueColSQL(queryString.toString(), alias) ;
		//false：为信息以存在
		if(count.intValue() > 0) {
			return false ;
		} else {
			return true;
		}
	}

	@Override
	public void adminChangePassword(UserDto dto) {
		if(null != dto && !dto.getIds().equals("")) {
			String[] ids = dto.getIds().split(",");
			for (String id : ids) {
				User user = super.getEntity(User.class, Integer.parseInt(id)) ;
				
				String pwd = encryptPassword(user.getUsername(), dto.getPassword(), user.getSalt()) ;
				super.executeSQL("update sys_user set password=? where id=?", new Object[]{pwd, id}) ;
				
				System.out.println("管理员修改用户密码，邮件通知[用户名："+user.getUsername()+", 密码："+dto.getPassword()+"]");
			}
		}
	}

	@Override
	public AjaxResponse changePassword(UserDto dto) {
		User user = super.getEntity(User.class, dto.getId()) ;
		if(null == dto.getPassword() || "".equals(dto.getPassword().trim())) {
			return new AjaxResponse(false, "密码不能为空！") ;
		} 
		
		if(!oldPasswordValidate(dto.getId(), dto.getOldPassword())) {
			return new AjaxResponse(false, "原密码不正确！") ;
		}
		
		String pwd = encryptPassword(user.getUsername(), dto.getPassword(), user.getSalt()) ;
		
		super.executeSQL("update sys_user set password=? where id=?", new Object[]{pwd, dto.getId()}) ;
		
		
		return new AjaxResponse(true, "密码修改成功，请重新登录！") ;
	}

	@Override
	public boolean oldPasswordValidate(Integer id, String oldPassword) {
		String queryString = "select t.* from sys_user t where t.id=?" ;
		UserDto user = (UserDto) super.findUniqueSQL(queryString, new Object[]{id}, UserDto.class, false) ;
		
		if(matches(user, oldPassword)) {
			return true ;
		} else {
			return false;
		}
	}

}
